// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com

// ReSharper disable CheckNamespace
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable CommentTypo
// ReSharper disable IdentifierTypo
// ReSharper disable InconsistentNaming
// ReSharper disable StringLiteralTypo
// ReSharper disable UnusedParameter.Local

/* Select.WithContextEnumerable.cs --
 * Ars Magna project, http://arsmagna.ru
 */

#region Using directives

using System;

#endregion

#nullable enable

namespace AM.Memory.Collections.Linq;

internal class SelectExprWithContextEnumerable<T, TR, TContext>
    : IPoolingEnumerable<TR>
{
    private IPoolingEnumerable<T>? _src;
    private Func<TContext, T, TR>? _condition;
    private TContext? _context;
    private int _count;

    public SelectExprWithContextEnumerable<T, TR, TContext> Init
        (
            IPoolingEnumerable<T> src,
            TContext context,
            Func<TContext, T, TR> condition
        )
    {
        _src = src;
        _count = 0;
        _context = context;
        _condition = condition;
        return this;
    }

    public IPoolingEnumerator<TR> GetEnumerator()
    {
        _count++;
        return Pool<SelectExprWithContextEnumerator>.Get()
            .Init (this, _src!.GetEnumerator(), _context!, _condition!);
    }

    private void Dispose()
    {
        if (_count == 0) return;
        _count--;

        if (_count == 0)
        {
            _src = default;
            _context = default;
            _condition = default;
            Pool<SelectExprWithContextEnumerable<T, TR, TContext>>.Return (this);
        }
    }

    internal class SelectExprWithContextEnumerator
        : IPoolingEnumerator<TR>
    {
        private TContext? _context;
        private Func<TContext, T, TR>? _condition;
        private IPoolingEnumerator<T>? _src;
        private SelectExprWithContextEnumerable<T, TR, TContext>? _parent;

        public SelectExprWithContextEnumerator Init
            (
                SelectExprWithContextEnumerable<T, TR, TContext> parent,
                IPoolingEnumerator<T> src,
                TContext context,
                Func<TContext, T, TR> condition
            )
        {
            _src = src;
            _parent = parent;
            _context = context;
            _condition = condition;
            return this;
        }

        public bool MoveNext() => _src!.MoveNext();

        public void Reset() => _src!.Reset();
        object IPoolingEnumerator.Current => Current!;

        public TR Current => _condition! (_context!, _src!.Current);

        public void Dispose()
        {
            _parent?.Dispose();
            _parent = default;
            _src?.Dispose();
            _src = default;
            _context = default;
            Pool<SelectExprWithContextEnumerator>.Return (this);
        }
    }

    IPoolingEnumerator IPoolingEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}
